/**
 * \file
 * \author  michal.nezerka@gmail.com
 * \brief   Implementation of Gpx class and all related classes
 */

//#include <wx/filename.h>
#include <iostream>
#include <wx/log.h>
#include <wx/xml/xml.h>

#include "exception.h"
#include "gpxdb.h"

using namespace wildwood;

GpxDb::GpxDb()
    : mDbState(eClosed)
{
}

GpxDb::~GpxDb()
{
    sqlite3_close(mDb);
    wxLogDebug(wxT("SQLite closed"));
}

void GpxDb::open(const wxString &dbFilePath)
{
    if (mDbState != eClosed)
        return;

    // open temporary (in-memory) database
    int rc = sqlite3_open(dbFilePath.ToAscii(), &mDb);
    if(rc)
    {
        wxLogError(wxT("Can't open SQLite database %s"), sqlite3_errmsg(mDb));
        throw Exception(wxT("Can't open SQLite database"));
    }
    wxLogDebug(wxT("SQLite DB opened successfully"));

    mDbState = eOpened;
    mDbFilePath = dbFilePath;
};

void GpxDb::create()
{
    // create tables
    wxString sql = "CREATE TABLE gpxs ("  \
        "creator    TEXT    DEFAULT NULL);";
    sqlExecute(sql);

    sql = "CREATE TABLE waypoints ("  \
        "id_parent  INT     NOT NULL," \
        "lat        REAL    NOT NULL DEFAULT 0," \
        "lon        REAL    NOT NULL DEFAULT 0);";
    sqlExecute(sql);

    sql = "CREATE TABLE tracks ("  \
        "id_gpx     INT     NOT NULL," \
        "name       TEXT," \
        "cmt        TEXT," \
        "dsc        TEXT);";
    sqlExecute(sql);

    sql = "CREATE TABLE segments (" \
        "id_track   INT     NOT NULL);";
    sqlExecute(sql);

    wxLogDebug(wxT("Tables created successfully"));

};

void GpxDb::sqlExecute(const wxString sql, int (*callback)(void*, int, char**, char**))
{
    char *sqlErrMsg = 0;

    int rc = sqlite3_exec(mDb, sql, callback, 0, &sqlErrMsg);
    if(rc != SQLITE_OK)
    {
        std::cout << "SQLite error: " << sqlErrMsg << std::endl;
        std::cout << "sql: " << sql << std::endl;
        sqlite3_free(sqlErrMsg);
    } else {
        std::cout << "Success: " << sql << std::endl;
    }
}

void GpxDb::sqlQuery(const wxString sql)
{
    char *sqlErrMsg = 0;
    sqlite3_stmt *ppStmt = NULL;
    int rc = sqlite3_prepare(mDb, sql, 0, &ppStmt, NULL);

    if(rc != SQLITE_OK)
    {
        std::cout << "SQLite error: " << sqlErrMsg << std::endl;
        std::cout << "sql: " << sql << std::endl;
        sqlite3_free(sqlErrMsg);
    } else {
        std::cout << "Success: " << sql << std::endl;
    }

};

sqlite3_int64 GpxDb::loadGpx(wxString path)
{
    // load and parse GPX XML file
    wxXmlDocument doc;
    if (!doc.Load(path))
        throw Exception(wxT("Error loading gpx"));

    // get and check root element
    wxXmlNode *rootNode = doc.GetRoot();

    if (rootNode->GetName() != wxT("gpx"))
        throw Exception(wxT("Invalid root XML element (expected: gpx)"));

    // get creator
    wxString mCreator = rootNode->GetAttribute(wxT("creator"));

    // insert new gpx
    wxString sql("INSERT INTO gpxs");
    if (mCreator == wxEmptyString) {
        sql += "(creator) VALUES(NULL);";
    } else {
        sql += " (creator) VALUES ('" + mCreator + "');";
    };
    sqlExecute(sql);
    sqlite3_int64 gpxRowId = sqlite3_last_insert_rowid(mDb);

    wxXmlNode *c = rootNode->GetChildren();
    while (c)
    {
        if (c->GetName() == wxT("trk"))
        {
            // insert new track
            wxString sql = wxString::Format(wxT("INSERT INTO tracks (id_gpx) VALUES (%llu)"), gpxRowId);
            sqlExecute(sql);
            sqlite3_int64 trackRowId = sqlite3_last_insert_rowid(mDb);

            wxXmlNode *trkc = c->GetChildren();
            while (trkc)
            {
                if (trkc->GetName() == wxT("trkseg"))
                {
                    // insert new segment
                    wxString sql = wxString::Format(wxT("INSERT INTO segments (id_track) VALUES (%llu)"), trackRowId);
                    sqlExecute(sql);
                    sqlite3_int64 segmentRowId = sqlite3_last_insert_rowid(mDb);

                    // read segment children (track points, etc.)
                    wxXmlNode *segc = trkc->GetChildren();
                    while (segc)
                    {
                        if (segc->GetName() == wxT("trkpt"))
                        {
                            // get mandatory attributes
                            wxString latStr = segc->GetAttribute(wxT("lat"));
                            wxString lonStr = segc->GetAttribute(wxT("lon"));
                            if (latStr != wxEmptyString || lonStr != wxEmptyString)
                            {
                                double lat,lon;
                                if (latStr.ToDouble(&lat) && lonStr.ToDouble(&lon))
                                {
                                    // insert new track point
                                    wxString sql = wxString::Format(wxT("INSERT INTO waypoints (id_parent, lat, lon) VALUES (%llu, %f, %f)"),
                                         segmentRowId, lat, lon);
                                    sqlExecute(sql);
                                    //sqlite3_int64 wptRowId = sqlite3_last_insert_rowid(mDb);
                                }
                            }
                        }
                        segc = segc->GetNext();
                    }
                }
                trkc = trkc->GetNext();
            }
            //wxXmlNode *t = c->GetChildren();
            //if (t && t->GetType() == wxXML_TEXT_NODE)
            //    mDescription = t->GetContent();

        }
        else if (c->GetName() == wxT(""))
        {
            //m_items.push_back(new SongBookSong(c));
        }
        else if (c->GetName() == wxT("section"))
        {
            //m_items.push_back(new SongBookSection(c));
        }
        c = c->GetNext();
    }

    return gpxRowId;
}

sqlite3_int64 GpxDb::createGpx()
{
    wxString sql("INSERT INTO gpxs (creator) VALUES ('WildWood');");
    sqlExecute(sql);
    sqlite3_int64 gpxId = sqlite3_last_insert_rowid(mDb);
    return gpxId;
}



